<template>
    <div class="talkContent">
        <div class="talkShow">
            <div :class="[(item.person=='mechanical')?'mechanicalTalk':'mineTalk']" v-for="(item,index) in talkList" :key="index">
                <span v-html="item.say"></span>
            </div>
            <!--            <div v-html="formattedContent"></div>-->
        </div>
        <div class="talkInput">
            <form @submit.prevent="start">
                <div class="right_layout_son_ipt">
                    <el-row :gutter="20">
                        <el-col :span="22">
                            <el-input
                                    placeholder="请输入想要查找的书籍类型，如动物、科幻等"
                                    v-model="userInput"
                                    maxlength="10"
                                    show-word-limit
                                    :autosize="{ minRows: 2}"
                                    resize="none"
                                    class="ipt">
                                <i slot="suffix" class="el-input__icon el-icon-position" style="cursor: pointer;" @click="start"></i>
                            </el-input>
                        </el-col>
                        <el-col :span="2">
                            <el-button @click="start" type="primary" class="btn" :loading="loading">{{ loading? 'ai正在思考':'提问' }}</el-button>
                        </el-col>
                    </el-row>
                </div>
            </form>
        </div>
    </div>
</template>

<script>
import CryptoJS from 'crypto-js';
import { Base64 } from "js-base64";
export default {
    data() {
        return {
            talkList: [
                { id: "1", person: 'mechanical', say: '你好，有什么可以帮到你呢？' },
            ],
            appId: 'cee2a9c3',
            status: 'init',
            ttsWS: null,
            totalRes: '',
            userInput: '',
            aiContentRequest: '',
            finalChat: [],
            loading:false,
            formattedContent: ''
        };
    },
    methods: {
        getWebsocketUrl() {
            return new Promise((resolve, reject) => {
                const apiKey = '1802c5c82a4aa017f61e812438cee5f1';
                const apiSecret = 'ZGI4M2U0NmY4ZGMwYmMxNjJkOWMzMzcy';
                const url = 'wss://spark-api.xf-yun.com/v4.0/chat'; //这里使用的是星火大模型1.x版本
                const host = "spark-api.xf-yun.com";
                let apiKeyName = "api_key";
                const date = new Date().toGMTString();
                console.log("鉴权url地址", date);
                const algorithm = 'hmac-sha256';
                const headers = 'host date request-line';
                const signatureOrigin = `host: ${host}\ndate: ${date}\nGET /v4.0/chat HTTP/1.1`;
                const signatureSha = CryptoJS.HmacSHA256(signatureOrigin, apiSecret);
                const signature = CryptoJS.enc.Base64.stringify(signatureSha);
                const authorizationOrigin = `${apiKeyName}="${apiKey}", algorithm="${algorithm}", headers="${headers}", signature="${signature}"`;
                const authorization = Base64.encode(authorizationOrigin);
                const finalUrl = `${url}?authorization=${authorization}&date=${encodeURI(date)}&host=${host}`;
                console.log(finalUrl)
                resolve(finalUrl);

                console.log("鉴权url地址2", url);
            });
        },
        setStatus(status) {
            this.status = status;
        },
        connectWebSocket() {
            this.setStatus('ttsing');
            this.getWebsocketUrl().then((url) => {
                let ttsWS;
                if ('WebSocket' in window) {
                    ttsWS = new WebSocket(url);
                } else if ('MozWebSocket' in window) {
                    ttsWS = new MozWebSocket(url);
                } else {
                    alert('浏览器不支持WebSocket');
                    return;
                }
                this.ttsWS = ttsWS;
                ttsWS.onopen = (e) => {
                    this.webSocketSend();
                };
                ttsWS.onmessage = (e) => {
                    this.result(e.data);
                };
                ttsWS.onerror = (e) => {
                    clearTimeout(this.playTimeout);
                    this.setStatus('error');
                    alert('WebSocket报错，请f12查看详情');
                    console.error(`详情查看：${encodeURI(url.replace('wss:', 'https:'))}`);
                };
                ttsWS.onclose = (e) => {
                    console.log(e);
                };
            });
        },
        webSocketSend() {
            let that = this
            const params = {
                header: {
                    app_id: this.appId,
                    uid: '随意',
                },
                parameter: {
                    chat: {
                        domain: '4.0Ultra',//如果是chat2这里也需要进行相应修改
                        temperature: 0.5,
                        max_tokens: 1024,
                    },
                },
                payload: {
                    message: {
                        text: [
                            {"role": "user", "content": "推荐三本关于"+that.userInput+"的畅销书,介绍作者、出版社、简介"}
                        ]
                    },
                },
            };
            console.log(JSON.stringify(params));
            this.ttsWS.send(JSON.stringify(params));
        },
        start() {
            this.loading = true
            this.totalRes = '';
            this.aiContentRequest = ''
            this.connectWebSocket();
        },
        requestHandle(requestData) {//处理request
            this.aiContentRequest = this.aiContentRequest + requestData.payload.choices.text[0].content
        },
        async result(resultData) {
            let jsonData = JSON.parse(resultData);
            this.totalRes += resultData;

            if (jsonData.header.status !== 2) { // 不为结束就进行添加
                this.requestHandle(jsonData);
            } else {
                let contentSomething = {
                    ai: this.aiContentRequest,
                    user: "推荐三本关于" + this.userInput + "的畅销书"
                };
                this.talkList.push({ id: "2", person: 'user', say: contentSomething.user });

                const data = contentSomething.ai;
                this.formattedContent = this.formatContent(data);
                console.info(this.formatContent(data));
                this.talkList.push({ id: "1", person: 'mechanical', say: '...' });

                let text = "";
                const length = this.talkList.length - 1; // 最后一个mechanicalTalk的索引
                for (let i = 0; i < this.formattedContent.length; i++) {
                    text += this.formattedContent.charAt(i);
                    await new Promise((resolve) => {
                        setTimeout(resolve, 50);
                    });
                    this.talkList[length] = { id: "1", person: 'mechanical', say: text };
                }

                this.userInput = '';
                this.loading = false;
            }

            if (jsonData.header.code !== 0) {
                alert(`提问失败: ${jsonData.header.code}:${jsonData.header.message}`);
                console.error(`${jsonData.header.code}:${jsonData.header.message}`);
                return;
            }

            if (jsonData.header.code === 0 && jsonData.header.status === 2) {
                this.ttsWS.close();
                this.setStatus('init');
            }
        },
        formatContent(content) {
            let formatted = content

                // 书名
                .replace(/(\d+\.\s*)(\*\*《[^》]*》\*\*)/g, '<br>$1<strong>$2</strong>')
                // 作者
                .replace(/(-\s*\*\*作者\*\*：)(.*)/g, '<br>$1<em><strong>$2</em></strong>')
                // 内容简介
                .replace(/(-\s*\*\*简介\*\*：)(.*)/g, '<br>$1<u>$2</u><br><br>')
                // 特点
                .replace(/(-\s*\*\*特点\*\*：)(.*)/g, '<br>$1<b>$2</b>')
                // 出版社
                .replace(/(-\s*\*\*出版社\*\*：)(.*)/g, '<br>$1<em><strong>$2</em></strong>')
                .replace(/\*/g, "");
            return formatted;
        },
    },
};
</script>

<style scoped>
.talkContent {
    margin: 50px auto 0;
    font-size: 14px;
}

.talkShow {
    margin-left: 50px;
    margin-right: 50px;
    height: 700px;
    overflow: scroll;
}

.talkInput {
    margin: 10px auto 0;
    display: flex;
}

.mechanicalTalk {
    margin: 10px;
}

.mechanicalTalk span {
    display: inline-block;
    background: white;
    border-radius: 10px;
    padding: 5px 10px;
    border: 1px solid rgb(214, 216, 219);
    border-top-left-radius: 0px;
    word-break: break-all;
    text-align: left;
}

.mineTalk {
    margin: 10px;
    text-align: right;
}

.mineTalk span {
    display: inline-block;
    border-radius: 10px;
    border-top-right-radius: 0px;
    background: #409eff;
    color: #fff;
    padding: 5px 10px;
    word-break: break-all;
    text-align: left;
}
.ipt {
    width: 120vh;
    margin: 10px 20px 10px 50px;
    padding: 10px 20px;
    border: 1px solid lightgray;
}
.right_layout_son_ipt {
    position: absolute;
    bottom: 0;
}
.btn {
    margin-top: 20px;
    width: 100px;
    border: none;
    padding: 10px 15px;
    background-color: #18a058;
    border-radius: 1px;
    color: white;
    font-size: 15px;
}
</style>